package base.dao;

import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;

/**
 * BaseDao扩展类，这类型下的方法会暴露hql语句及一些数据访问层的逻辑对象
 * 如果采用严格的分层模型，则继承BaseDao
 * 如果为了编程方便，则可以继承此类
 * @author 打倒小日本
 * @param <T> 管理的对象类型
 */
public class BaseExtendDao<T> extends BaseDao<T>
{
	@SuppressWarnings("unchecked")
	protected List criteriaUtil(int firstResult, int maxResults, Order[] orders, Criterion... criterion)
	{
		Criteria crit = getSession().createCriteria(getEntityClass());
		for (Criterion c : criterion)
		{
			crit.add(c);
		}

		for (Order order : orders)
		{
			crit.addOrder(order);
		}

		if (firstResult != 0 || maxResults != Integer.MAX_VALUE)
		{
			crit.setFirstResult(firstResult);
			crit.setMaxResults(maxResults);
		}

		return crit.list();
	}
	
	@SuppressWarnings("unchecked")
	protected List hqlUtil(int firstResult, int maxResults, String hql, Object... values)
	{
		Query query = getSession().createQuery(hql);
		for (int i = 0; i < values.length; i++)
		{
			Object value = values[i];
			query.setParameter(i, value);
		}

		if (firstResult != 0 || maxResults != Integer.MAX_VALUE)
		{
			query.setFirstResult(firstResult);
			query.setMaxResults(maxResults);
		}

		return query.list();
	}
	
	@SuppressWarnings("unchecked")
	protected List hqlUtil(int firstResult, int maxResults, String hql, Map map)
	{
		Query query = getSession().createQuery(hql);

		Iterator<Map.Entry<String, Object>> iter = map.entrySet().iterator();
		while (iter.hasNext())
		{
			Map.Entry<String, Object> entry = iter.next();
			String key = entry.getKey();
			Object value = entry.getValue();
			if (value instanceof List)
			{
				query.setParameterList(key, (List) value);
			} else
			{
				query.setParameter(key, value);
			}
		}

		if (firstResult != 0 || maxResults != Integer.MAX_VALUE)
		{
			query.setFirstResult(firstResult);
			query.setMaxResults(maxResults);
		}

		return query.list();
	}
	
	/**
	 * 通过Criterion对象，设置查询条件
	 * @param criterion
	 * @return
	 */
	public int countByCriteria(Criterion... criterion)
	{
		Criteria crit = getSession().createCriteria(getEntityClass());
		for (Criterion c : criterion)
		{
			crit.add(c);
		}
		
		return (Integer) crit.setProjection(Projections.rowCount()).uniqueResult();
	}
	
	/**
	 * 通过Criterion对象，设置查询条件
	 * @param criterion
	 * @return
	 */
	public Object getByCriteria(Criterion... criterion)
	{
		Criteria crit = getSession().createCriteria(getEntityClass());
		for (Criterion c : criterion)
		{
			crit.add(c);
		}
		
		return crit.uniqueResult();
	}
	
	/**
	 * 通过Criterion对象，设置查询条件
	 * @param criterion
	 * @return
	 */
	public List findByCriteria(Criterion... criterion)
	{
		return findByCriteria(0, Integer.MAX_VALUE, criterion);
	}
	
	/**
	 * 通过Criterion对象，设置查询条件，支持分页
	 * @param firstResult
	 * @param maxResults
	 * @param criterion
	 * @return
	 */
	public List findByCriteria(int firstResult, int maxResults, Criterion... criterion)
	{
		return findByCriteria(firstResult, maxResults, Order.asc(getIdName()), criterion);
	}
	
	/**
	 * 通过Criterion对象，设置查询条件，支持排序
	 * @param order
	 * @param criterion
	 * @return
	 */
	public List findByCriteria(Order order, Criterion... criterion)
	{
		return findByCriteria(0, Integer.MAX_VALUE, order, criterion);
	}
	
	/**
	 * 通过Criterion对象，设置查询条件，支持排序，支持分页
	 * @param firstResult
	 * @param maxResults
	 * @param order
	 * @param criterion
	 * @return
	 */
	public List findByCriteria(int firstResult, int maxResults, Order order, Criterion... criterion)
	{
		return findByCriteria(firstResult, maxResults, new Order[] {order}, criterion);
	}
	
	/**
	 * 通过Criterion对象，设置查询条件，支持排序
	 * @param orders
	 * @param criterion
	 * @return
	 */
	public List findByCriteria(Order[] orders, Criterion... criterion)
	{
		return findByCriteria(0, Integer.MAX_VALUE, orders, criterion);
	}
	
	/**
	 * 通过Criterion对象，设置查询条件，支持排序，支持分页
	 * @param firstResult
	 * @param maxResults
	 * @param orders
	 * @param criterion
	 * @return
	 */
	public List findByCriteria(int firstResult, int maxResults, Order[] orders, Criterion... criterion)
	{
		return criteriaUtil(firstResult, maxResults, orders, criterion);
	}
	
	/**
	 * 根据hql查询
	 * @param hql
	 * @param values
	 * @return
	 */
	public Object getByHql(String hql, Object... values)
	{
		Query query = getSession().createQuery(hql);
		
		for (int i = 0; i < values.length; i++)
		{
			Object value = values[i];
			query.setParameter(i, value);
		}

		return query.uniqueResult();
	}
	
	/**
	 * 根据hql查询
	 * 此处map属性不要加泛型，否则当泛型条件不完全满足时，会自动匹配getByHql(String hql, Object... values)方法，造成混乱
	 * @param hql
	 * @param map
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public Object getByHql(String hql, Map map)
	{
		Query query = getSession().createQuery(hql);
		
		Iterator<Map.Entry> iter = map.entrySet().iterator();
		while (iter.hasNext())
		{
			Map.Entry entry = iter.next();
			String key = (String) entry.getKey();
			Object value = entry.getValue();
			if (value instanceof List)
			{
				query.setParameterList(key, (List) value);
			}
			else
			{
				query.setParameter(key, value);
			}
		}
		
		return query.uniqueResult();
	}

	/**
	 * 根据hql查询
	 * @param hql
	 * @param values
	 * @return
	 */
	public List findByHql(String hql, Object... values)
	{
		return findByHql(0, Integer.MAX_VALUE, hql, values);
	}
	
	/**
	 * 根据hql查询，支持分页
	 * @param firstResult
	 * @param maxResults
	 * @param hql
	 * @param values
	 * @return
	 */
	public List findByHql(int firstResult, int maxResults, String hql, Object... values)
	{
		return hqlUtil(firstResult, maxResults, hql, values);
	}
	
	/**
	 * 根据hql查询
	 * 此处map属性不要加泛型，否则当泛型条件不完全满足时，会自动匹配findByHql(String hql, Object... values)方法，造成混乱
	 * @param hql
	 * @param map
	 * @return
	 */
	public List findByHql(String hql, Map map)
	{
		return findByHql(0, Integer.MAX_VALUE, hql, map);
	}
	
	/**
	 * 根据hql查询，支持分页
	 * 此处map属性不要加泛型，否则当泛型条件不完全满足时，会自动匹配findByHql(int firstResult, int maxResults, String hql, Object... values)方法，造成混乱
	 * @param firstResult
	 * @param maxResults
	 * @param hql
	 * @param map
	 * @return
	 */
	public List findByHql(int firstResult, int maxResults, String hql, Map map)
	{
		return hqlUtil(firstResult, maxResults, hql, map);
	}
}
